﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace ImageProcessing
{
	public static class EdgeFilters
	{
		private static double[,] PrewittX = {
			{-1,-1,-1},
			{0,0,0},
			{1,1,1}
		};

		private static double[,] PrewittY = {
			{-1,0,1},
			{-1,0,1},
			{-1,0,1}
		};

		private static double[,] SobelX = {
			{-1,-2,-1},
			{0,0,0},
			{1,2,1}
		};

		private static double[,] SobelY = {
			{-1,0,1},
			{-2,0,2},
			{-1,0,1}
		};


		internal static Bitmap SobelPrewitt(Bitmap bmIn, bool isPrewitt)
		{
			double[][] adY = ColorConversions.ImagetoY(bmIn, true);
			double[][] adConverted = new double[bmIn.Width][];
			int nWinLen = 3;
			for (int i = 0; i < bmIn.Width; i++)
			{
				adConverted[i] = new double[bmIn.Height];
			} //end for
			int nWinJ, nWinI;
			int k;

			double[] adPixel = new double[3];
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height, bmIn.PixelFormat);

			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectSrc, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				byte* dptr = (byte*)(void*)destPtr;

				//calculate values
				for (int j = 0; j < bmOut.Height; j++)
				{
					k = j * srcStride;
					for (int i = 0; i < bmOut.Width; i++)
					{
						nWinJ = Math.Max(j - 1, 0);


						//walk through window and sum intesity (Y) values
						adPixel[0] = 0;
						adPixel[1] = 0;
						for (int n = 0; n < nWinLen; n++)
						{
							nWinI = Math.Max(i - 1,0);
							for (int m = 0; m < nWinLen; m++)
							{
								if (isPrewitt)
								{
									adPixel[0] += adY[nWinI][nWinJ] * PrewittX[m,n];
									adPixel[1] += adY[nWinI][nWinJ] * PrewittY[m, n];
								} //end if
								else
								{
									adPixel[0] += adY[nWinI][nWinJ] * SobelX[m, n];
									adPixel[1] += adY[nWinI][nWinJ] * SobelY[m, n];
								} //end else
								nWinI++;
								if (nWinI >= bmOut.Width)
									nWinI--;
							}
							nWinJ++;
							if (nWinJ >= bmOut.Height)
								nWinJ--;
						}

						adConverted[i][j] = Math.Abs(adPixel[0]) + Math.Abs(adPixel[1]);
						adPixel = ColorConversions.YIQConversion(adConverted[i][j]);

						dptr[i * srcBytePP + k] = (byte)(adPixel[0] * 255.0);
						if (srcBytePP >= 3)
						{
							dptr[i * srcBytePP + k + 1] = (byte)(adPixel[1] * 255.0);
							dptr[i * srcBytePP + k + 2] = (byte)(adPixel[2] * 255.0);
							if (srcBytePP == 4)
								dptr[i * srcBytePP + k + 3] = 255;
						} //end if

					} //end for
				} //end for
			}
			bmOut.UnlockBits(srcBitData);
			bmIn.UnlockBits(srcBitData);
			return bmOut;
		}//end 

	}
}
